package yuanxin

import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"gitee.com/botaoshow/yuanxin/web/common/conf"
	"gitee.com/botaoshow/yuanxin/web/log"
	"gitee.com/botaoshow/yuanxin/web/response"

	"github.com/gin-gonic/gin"
)

// Start 运行服务（平滑关闭）
func start(port string, r http.Handler) {
	// 创建HTTP服务器
	srv := &http.Server{
		Addr:    port,
		Handler: r,
	}

	// 在goroutine中启动服务器
	go func() {
		if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			panic(err)
		}
	}()

	// 等待中断信号以优雅地关闭服务器
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	fmt.Println("服务器正在关闭...")
	// 设置超时时间来优雅地关闭服务器
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := srv.Shutdown(ctx); err != nil {
		fmt.Println("服务器关闭错误:", err)
	}
	fmt.Println("服务器已关闭")

}

var isRunning bool
var onInitArr []func()
var onStartArr []func()
var onCloseArr []func()

func OnInit(f func()) {
	if isRunning {
		panic("OnInit() can only be called once")
	}
	onInitArr = append(onInitArr, f)
}
func OnStart(f func()) {
	if isRunning {
		panic("OnStart() can only be called once")
	}
	onStartArr = append(onStartArr, f)
}
func OnClose(f func()) {
	if isRunning {
		panic("OnClose() can only be called once")
	}
	onCloseArr = append(onCloseArr, f)
}

func RunApp(setupRouter func(engine *gin.Engine)) {
	isRunning = true
	conf.InitConf("conf.yaml")
	var isDebug = conf.AppConfig.Server.Mode == "debug"
	if isDebug {
		log.InitDevLogger()
	} else {
		log.InitProdLogger()
	}
	if len(onInitArr) > 0 {
		for _, f := range onInitArr {
			f()
		}
	}
	// 设置运行模式
	gin.SetMode(conf.AppConfig.Server.Mode)
	r := gin.New()
	r.Static("/static", "./static")
	r.StaticFile("/favicon.ico", "./static/favicon.ico")
	//r.LoadHTMLGlob("templates/**/*")
	r.Use(gin.Recovery())
	// 添加日志中间件
	//r.Use(middleware.LoggerHandler(log.Logger))
	r.NoRoute(func(c *gin.Context) {
		response.Resp(c, response.CodeNotFound, "404 Not Found", nil)
	})
	r.NoMethod(func(c *gin.Context) {
		response.Resp(c, response.CodeMethodNotAllowed, "405 Method Not Allowed", nil)
	})
	setupRouter(r)
	if len(onStartArr) > 0 {
		for _, f := range onStartArr {
			f()
		}
	}
	start(conf.AppConfig.Server.Port, r)
	if len(onCloseArr) > 0 {
		for _, f := range onCloseArr {
			f()
		}
	}
}
